package com.zj.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.NonNull;

/**
 * @author 赵赳
 * @since 2021/12/22 10:56
 */
public class BeanCopier {

  /**
   * 拷贝
   *
   * @param source 源对象
   * @param target 目标对象
   * @return 拷贝完成的对象
   */
  @NonNull
  public static <S, T> T copy(@NonNull S source, @NonNull T target) {
    BeanUtils.copyProperties(source, target);
    return target;
  }

  /**
   * 对象拷贝, 使用Spring BeanUtils进行封装
   *
   * @param source      源对象
   * @param targetClass 目标类
   * @return 拷贝后的目标对象
   * @see org.springframework.beans.BeanUtils
   */
  public static <S, T> T copy(@NonNull S source, @NonNull Class<T> targetClass) {
    return copy(source, () -> BeanUtils.instantiateClass(targetClass));
  }


  public static <S, T> T copy(@NonNull S source, Supplier<T> supplier) {
    var target = supplier.get();
    BeanUtils.copyProperties(source, target);
    return target;
  }

  /**
   * 实体类非空属性转map
   *
   * @param bean 实体类
   */
  public static <T> Map<String, Object> beanToMap(@NonNull T bean) {
    Map<String, Object> map = new HashMap<>(bean.getClass().getDeclaredFields().length);
    Arrays.stream(bean.getClass().getDeclaredFields()).forEach(field -> setMap(field, bean, map));
    return map;
  }

  /**
   * 获取字段的值map
   *
   * @param field 对象属性
   */
  public static <T> void setMap(Field field, T bean, Map<String, Object> map) {
    field.setAccessible(true);
    try {
      Object fieldValue = field.get(bean);
      if (Objects.nonNull(fieldValue)) {
        map.put(field.getName(), fieldValue);
      } else {
        map.put(field.getName(), null);
      }
    } catch (IllegalAccessException e) {
      throw new RuntimeException("BeanCopier 对象拷贝出现异常", e);
    }
  }


  /**
   * Map 转 Object
   *
   * @param map       需要转换的map数据
   * @param beanClass 需要转换的Class类型
   * @return Object 对象
   */
  public static <T> T mapToBean(@NonNull Map<String, Object> map, @NonNull Class<T> beanClass) {
    var object = BeanUtils.instantiateClass(beanClass);
    Field[] fields = object.getClass().getDeclaredFields();
    for (Field field : fields) {
      int mod = field.getModifiers();
      if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
        continue;
      }
      field.setAccessible(true);
      try {
        field.set(object, map.get(field.getName()));
      } catch (IllegalAccessException e) {
        throw new RuntimeException("BeanCopier mapToBean出现异常", e);
      }
    }
    return object;
  }


}
